#include "ET++.ph"
#ifdef __GNUG__
#pragma implementation
#endif

#include "MethodAccessor.h"

#include "Class.h"
#include "OrdColl.h"
#include "PathLookup.h"
#include "String.h"
#include "System.h"
#include "CheapText.h"
#include "CodeTextView.h"
#include "ET_stdio.h"

#include "EtPeManager.h"

const int cMaxName= 400;

//---- PeMethodAccessor --------------------------------------------------------

PeMethodAccessor::PeMethodAccessor()
{
}

Collection *PeMethodAccessor::FindMethods(Class*, PathLookup*)
{
	AbstractMethod("FindMethods");
	return 0;
}

//---- PeMapMethodAccessor -----------------------------------------------------

static const char
	*dtor= "_dtor",
	*ctor= "_ctor";

PeMapMethodAccessor::PeMapMethodAccessor()
{
}

const char *PeMapMethodAccessor::GetMapFileName(Class *cl, PathLookup *universe)
{
	static char mappathname[2*cMaxName];
	const char *base= cl->GetImplFileName();
	const char *bp= strrchr(base, '/');
	if (bp)
		base= ++bp;   // skip '/'

	if (universe->Lookup(form(".MAP/%s.map", base), mappathname, 4))
		return mappathname;
	return 0;
}

Collection *PeMapMethodAccessor::FindMethods(Class *cl, PathLookup *universe)
{
	OrdCollection *oc= new OrdCollection;
	const char *mapfile= GetMapFileName(cl, universe);

	if (mapfile) {
		IStream fp(mapfile);

		if (fp) {
			char classname[cMaxName], methodname[cMaxName], clname[cMaxName];
			int line, pub;
	
			// assumption: method is translated to _class_method
			sprintf(clname, "_%s_", cl->Name());
			while (fp >> classname >> methodname >> line >> pub) {
				if (strncmp(methodname, clname, strlen(clname)) == 0) {
					// change _ctor and & _dtor
					char *name= methodname+strlen(clname);
					if (strncmp(name, dtor, strlen(dtor)) == 0)
						name= form("~%s", cl->Name());
					else if (strncmp(name, ctor, strlen(ctor)) == 0)
						name= form("+%s(%s)", cl->Name(), name+strlen(ctor));
					oc->Add(new PeMethodReference(line, cl, name, pub == 2));
				}
			}
		}
	}
	return oc;
}

//---- MethodScanner -----------------------------------------------------------

class MethodScanner: public CodeAnalyzer {
	Collection *cp;
	const char *cname;
	Class *clp;
protected:
	void Function(int line, int start, int end, const char *name, const char *classname);
public:
	MethodScanner(Text *t, Collection *cp, Class *clp);
};

MethodScanner::MethodScanner(Text *t, Collection *c, Class *classp)
																: CodeAnalyzer(t)
{
	cp= c;
	clp= classp;
	cname= clp->Name();
}

void MethodScanner::Function(int line, int, int, const char *name, const char *clname)
{
	if (clname && strcmp(clname, cname) == 0)
		cp->Add(new PeMethodReference(line, clp, name, TRUE));
}

//---- PeScanMethodAccessor ----------------------------------------------------

PeScanMethodAccessor::PeScanMethodAccessor()
{
}

Collection *PeScanMethodAccessor::FindMethods(Class *cl, PathLookup*)
{
	OrdCollection *oc= new OrdCollection;
	char filename[1000];
	if (!gEtPeManager->FileOfClass(cl, filename, FALSE))
		return 0;
	IStream fp(filename);
	CheapText text(5000);
	text.ReadFromAsPureText(fp);
	MethodScanner ms(&text, oc, cl);
	ms.Doit();
	return oc;
}

